package com.example.baselib.http;

import android.util.Log;

import com.example.baselib.BaseRepository;
import com.example.baselib.databean.ResponseData;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

import javax.annotation.Nullable;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okio.Buffer;
import retrofit2.Converter;
import retrofit2.Retrofit;

import static okhttp3.internal.Util.UTF_8;

/**
 * Author: sxygsj
 * Date: 2020/4/17 13:28
 * Description: 自定义GsonFactory 对code 和msg 做控制
 * History: 感觉太扯了。。。不好 TODO 要换网络请求
 * <author> <time> <version> <desc>
 * 作者姓名 修改时间 版本号
 */
public class CustomGsonConverterFactory extends Converter.Factory {

    /**
     * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static CustomGsonConverterFactory create() {
        return create(new Gson());
    }

    /**
     * Create an instance using {@code gson} for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
    public static CustomGsonConverterFactory create(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        return new CustomGsonConverterFactory(gson);
    }

    private final Gson gson;

    private CustomGsonConverterFactory(Gson gson) {
        this.gson = gson;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        Log.i("main", "responseBodyConverter: " + type.toString());
        return new CustomGsonResponseBodyConverter<>(gson, adapter);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonRequestBodyConverter<>(gson, adapter);
    }


}

class CustomGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private final Gson gson;
    private final TypeAdapter<T> adapter;

    public CustomGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Nullable
    @Override
    public RequestBody convert(T value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}

/**
 * @author sxygsj.
 * @creat time 2020/4/17 14:24.
 * @description [解析 ResponseBody,通过 抛异常 对code 处理]
 * @chang time 2020/4/17 14:24.
 * @chang describe []
 */
class CustomGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final TypeAdapter<T> adapter;

    public CustomGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;

    }

    @Nullable
    @Override
    public T convert(ResponseBody value) throws IOException {
        try {
            String body = value.string();
            JSONObject jsonObject = null;
            try {
                jsonObject = new JSONObject(body);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            int code = 0;
            String msg = "";
            String data = "";
            try {
                code = jsonObject.getInt("code");
                msg = jsonObject.getString("msg");
                if (code != 0) {
                    throw new BodyException(msg);
                }
                data = jsonObject.getJSONArray("data").toString();
                if (data.equals("[]")){
                    throw new BodyException("暂无数据");
                }
                return (T) new ResponseData<String>(code, msg, data); //针对泛型的只能返回json串
            } catch (JSONException e) {
                e.printStackTrace();
            }
            try {
                code = jsonObject.getInt("code");
                msg = jsonObject.getString("msg");
                if (code != 0) {
                    throw new BodyException(msg);
                }
                data = jsonObject.getString("data");
                if (data=="null"||data.isEmpty()){
                    throw new BodyException("暂无数据");
                }
                return (T) new ResponseData<String>(code, msg, data); //针对泛型的只能返回json串
            } catch (JSONException e) {
                e.printStackTrace();
            }
            T result = null;
            MediaType mediaType = value.contentType();
            Charset charset = mediaType != null ? mediaType.charset(UTF_8) : UTF_8;
            InputStream inputStream = new ByteArrayInputStream(body.getBytes());
            JsonReader jsonReader = gson.newJsonReader(new InputStreamReader(inputStream, charset));
            result = adapter.read(jsonReader);
            if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
                throw new JsonIOException("JSON document was not fully consumed.");
            }
            return result;
        } finally {
            value.close();
        }

    }
}

class BodyException extends RuntimeException {
    public BodyException(String msg) {
        super(msg);
    }
}